#pragma once
#ifndef _KH_ENGINE_ACTOR_H
#define _KH_ENGINE_ACTOR_H
#include <Kharlia/Engine/Common.h>
#include <Kharlia/Engine/Units.h>
#include <Kharlia/Engine/Drawable.h>
#include <Kharlia/Engine/Net.h>
#include <Kharlia/Core/Tasker.h>

#define KH_DEF_SET_NV(TYPE, NAME) inline void Set##NAME(TYPE InValue) { m##NAME = InValue; mNetDirty = true; }
#define KH_DEF_GETSET_NV(TYPE, NAME) KH_DEF_GET(TYPE, NAME) KH_DEF_SET_NV(TYPE, NAME)

#undef Yield // From WinBase.h

namespace kharlia { namespace engine {

void _InitActorClasses();
void _ExitActorClasses();
class ATransform;
void _MemberTest(shared_ptr<ATransform> t);

class CLevel;
class CWorld;
class CEngine;
class CClient;
class CActorReplicator;
class CPlayer;
class APawn;

enum EActorRenderType {
    ART_NONE,
    ART_IMAGE,
    ART_ANI
};

enum EDirection {
    DIR_NORTH,
    DIR_WEST,
    DIR_SOUTH,
    DIR_EAST,
    DIR_NORTHWEST,
    DIR_SOUTHWEST,
    DIR_SOUTHEAST,
    DIR_NORTHEAST,
};

union FTileGroupNumber {
    uint16 Number;
    struct {
        uint8 X;
        uint8 Y;
    };

    FTileGroupNumber(): Number(0) {}
    FTileGroupNumber(uint16 n): Number(n) {}

    inline bool operator==(const FTileGroupNumber& other) const { return Number == other.Number; }
    inline bool operator!=(const FTileGroupNumber& other) const { return Number != other.Number; }
    inline operator uint16() const { return Number; }
};

class CActor;
class CGame;

/// Base class for all actor components.
/// Note that all component classes are prefixed with "A" rather than "C".
class KH_ENGINE_DECLSPEC AComponent: public core::CObject {
    /// The actor this component is bound to.
    /// The component is considered uninitialized if this is None.
    shared_ptr<CActor> mOwner;
    /// Convenient access to the owner's level.
    shared_ptr<CLevel> mLevel;
    /// True when this component, and therefore the actor, shouldn't be
    /// deleted while the game is started.
    bool mNoDelete;
    /// Tick priority of this component. Lower priority components are
    /// ticked first. A component that depends on another component should
    /// higher priority number.
    sint16 mPriority;

    KH_DECL_GC()

protected:
    /// True when a network replicated variable has been changed by
    /// Python or C++.
    bool mNetDirty;
    /// True when it is the component's first time to be replicated.
    bool mNetInitial;
    /// True when the machine we're replicating to owns this component
    bool mNetOwner;

    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();
    
    void _SendEventArgs(const object& name, const object& args) {}
    void _OnRecvGameStarted(shared_ptr<CGame> game);
    void _OnRecvGameStopped();

    /// A check to ensure a required component is defined.
    /// Raises an exception with type information if ref is empty.
    template <class T>
    void EnsureComponent(shared_ptr<T>& ref, bool create=false);

    KH_DEF_SET(bool, NoDelete)
    KH_DEF_SET(sint16, Priority)
    //KH_DECL_CLASSINFO()

public:
    AComponent(PyObject* self);
    virtual ~AComponent() {}

    /// Initialize the component with its owner
    kh_pycall void OnInit(shared_ptr<CActor> owner);
    /// Finalize the component, clears the owner
    kh_pycall void OnExit();
    /// Standard update
    virtual void Tick(float deltaTime);

    kh_pycall void StartMsgProc();
    kh_pycall void StopMsgProc();

    //object CreateEventTasklet(const object& name,
    //                          uint8 group=core::CTasker::CURRENT_GROUP,
    //                          const object& args=make_tuple());

    kh_pycall void SendMsgArgs(const object& name, const object& args=py::make_tuple());

    void SendGameStarted(shared_ptr<CGame> game);
    void SendGameStopped();

    /// Returns a handle to the instance's Python type.
    handle<PyTypeObject> GetTypeHandle() const;

    /// True if the component has been initialized
    bool GetInited() const;

    void ResetLevel();

    KH_DEF_GET(const shared_ptr<CActor>&, Owner)
    KH_DEF_GET(const shared_ptr<CLevel>&, Level)
    KH_DEF_GET(bool, NoDelete)
    KH_DEF_GET(sint16, Priority)
    KH_DEF_GET(bool, NetDirty)
    KH_DEF_GET(bool, NetInitial)
    KH_DEF_GET(bool, NetOwner)

    /// Comparison to allow sorting by priority
    bool operator<(const AComponent& other) const { return mPriority < other.mPriority; }

    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

inline void AComponent::OnInit(shared_ptr<CActor> owner) {
    call_method<void>(mSelf, "OnInit", owner);
}

inline void AComponent::OnExit() {
    call_method<void>(mSelf, "OnExit");
}

inline void AComponent::StartMsgProc() {
    call_method<void>(mSelf, "StartMsgProc");
}

inline void AComponent::StopMsgProc() {
    call_method<void>(mSelf, "StopMsgProc");
}

//inline object AComponent::CreateEventTasklet(const char* name, uint8 group, const object& args) {
//    return CreateEventTasklet(str(name), group, args);
//}

inline bool AComponent::GetInited() const {
    return mOwner;
}

C_ASSERT(sizeof(uint32) == sizeof(PyObject*));

inline handle<PyTypeObject> AComponent::GetTypeHandle() const {
    return handle<PyTypeObject>(borrowed(Py_TYPE(mSelf)));
}

template <class T>
inline void AComponent::EnsureComponent(shared_ptr<T>& ref, bool create) {
    if (!ref) {
        str ownerName(mOwner);
        format msg("component is missing dependency: required_type=%1%, this_type=%2%, owner=%3%");
        msg % typeid(T).name();
        msg % typeid(*this).name();
        msg % extract<char*>(ownerName);
        throw RuntimeError(msg);
    }
    return;
}

inline void AComponent::SendMsgArgs(const object& name, const object& args) {
    call_method<void>(mSelf, "SendMsgArgs", name, args);
}

inline void AComponent::SendGameStarted(shared_ptr<CGame> game) {
    SendMsgArgs(str("GameStarted"), py::make_tuple(game));
}

inline void AComponent::SendGameStopped() {
    SendMsgArgs(str("GameStopped"));
}

/// A transform component representing an actor's position in the world.
/// Will support scale and rotation in the future if necessary.
class KH_ENGINE_DECLSPEC ATransform: public AComponent {
    /// The actor's position.
    FVector3F mPosition;
    /// A tile group number created from the position within the level.
    /// This is used to speed up searches for actors in specific locations.
    FTileGroupNumber mTileGroupNumber;

    /// Update the tile group number based on Position.
    void ResetTileGroupNumber();

protected:
    KH_DECL_CLASSINFO()

public:
    ATransform(PyObject* self): AComponent(self), mTileGroupNumber(0) {}
    virtual ~ATransform() {}

    //virtual void _OnInit(shared_ptr<CActor> owner);
    //virtual void _OnExit();
    virtual void Tick(float deltaTime) {}
    
    /// Move the actor by delta.
    /// Despite this being defined in AMovement, the actual
    /// movement function requires transform and physics components.
    virtual void Move(const FVector3F& delta);

    KH_DEF_GETSET_NV(const FVector3F&, Position)
    void AddPosition(const FVector3F& delta);
    KH_DEF_GET(FTileGroupNumber, TileGroupNumber)

    /// Returns the tile group number for pos.
    static FTileGroupNumber CalculateTileGroupNumber(const FVector3F& pos);

    friend void _InitActorClasses();
    friend void _InitActorBindings();
    friend void _MemberTest(shared_ptr<ATransform> t);
};

inline void ATransform::ResetTileGroupNumber() {
    mTileGroupNumber = CalculateTileGroupNumber(mPosition);
}

inline void ATransform::AddPosition(const FVector3F& delta) {
    mPosition += delta;
    mNetDirty = true;
}

inline FTileGroupNumber ATransform::CalculateTileGroupNumber(const FVector3F& pos) {
    FTileGroupNumber n;
    n.X = int(pos.X) / 64;
    n.Y = int(pos.Y) / 64;
    return n;
}

/// A movement component. Stores information about the actor's velocity and
/// acceleration.
class KH_ENGINE_DECLSPEC AMovement: public AComponent {
    /// Velocity in tiles per second.
    FVector3F mVelocity;
    /// Acceleration applied to velocity during Tick().
    FVector3F mAcceleration;
    /// Maximum allowed velocity in absolute values.
    FVector3F mMaxVelocity;
    /// Maximum allowed acceleration in absolute values.
    FVector3F mMaxAcceleration;
    /// The owner's transform component.
    shared_ptr<ATransform> mTransform;

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

    KH_DECL_CLASSINFO()

public:
    AMovement(PyObject* self): AComponent(self) {}
    virtual ~AMovement() {}

    virtual void Tick(float deltaTime);

    KH_DEF_GETSET_NV(const FVector3F&, Velocity)
    KH_DEF_GETSET_NV(const FVector3F&, Acceleration)
    KH_DEF_GETSET_NV(const FVector3F&, MaxVelocity)
    KH_DEF_GETSET_NV(const FVector3F&, MaxAcceleration)

    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

/// A rendering component. Provides information that the engine needs
/// to render the actor.
// TODO: Make this an abstract base and create ASprite and AAnimation
class KH_ENGINE_DECLSPEC ARender: public AComponent, public FDrawable {
    /// The way to render the actor
    EActorRenderType mRenderType;
    /// The direction the sprite points in
    EDirection mDirection;
    /// Whether or not to render the actor
    bool mHidden;
    /// The owner's transform component.
    shared_ptr<ATransform> mTransform;

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

    KH_DECL_CLASSINFO()

public:
    ARender(PyObject* self):
         AComponent(self),
         mRenderType(ART_IMAGE),
         mDirection(DIR_SOUTH),
         mHidden(false) {}
    virtual ~ARender() {}

    virtual void Tick(float deltaTime) {}
    /// Draw this component's actor using the engine's render interface
    void Draw(CClient& client);

    KH_DEF_GETSET_NV(EActorRenderType, RenderType)
    KH_DEF_GETSET_NV(EDirection, Direction)
    KH_DEF_GETSET_NV(bool, Hidden)
    KH_DEF_GET(const shared_ptr<ATransform>&, Transform)
    
    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

/// A physics component. Provides the actor's bounding box along with
/// information about what it can collide with.
class KH_ENGINE_DECLSPEC APhysics: public AComponent {
    /// True when the actor should collide with tiles
    bool mCollideTiles;
    /// True when the actor should collide with actors
    bool mCollideActors;
    /// True when the actor should block other actors
    bool mBlockActors;
    /// The layer of the level to be used for collision checks
    int mCollisionLayer;
    /// The actor's bounding box, can have negative offset.
    FRectF mBounds;
    /// The time when this actor last collided, used to prevent too
    /// many calls to collision events.
    float mLastActorHitTime;
    /// The actor we hit last. This pointer is only used for equality checking
    /// and should never be used
    // TODO: Make this store the actor's name hash instead.
    CActor* mLastActorHit; // used only for checking in MoveActor()
    /// The owner's transform component
    shared_ptr<ATransform> mTransform;

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

    KH_DECL_CLASSINFO()

public:
    APhysics(PyObject* self);
    virtual ~APhysics() {}
    virtual void Tick(float deltaTime) {}

    void _OnTouched(shared_ptr<APhysics> other);
    /// Called when this collides with another or is collided into by
    /// another.
    /// \pycall
    void OnTouched(shared_ptr<APhysics> other);
    void SendTouched(shared_ptr<APhysics> other);

    KH_DEF_GETSET_NV(bool, CollideTiles)
    KH_DEF_GETSET_NV(bool, CollideActors)
    KH_DEF_GETSET_NV(int, CollisionLayer)
    KH_DEF_GETSET_NV(const FRectF&, Bounds)
    KH_DEF_GET(const shared_ptr<ATransform>&, Transform)
    
    friend void _InitActorClasses();
    friend void _InitActorBindings();
    friend class CLevel;
};

inline void APhysics::OnTouched(shared_ptr<APhysics> other) {
    call_method<void>(mSelf, "OnTouched", other);
}

inline void APhysics::SendTouched(shared_ptr<APhysics> other) {
    SendMsgArgs(str("Touched"), py::make_tuple(other));
}

class KH_ENGINE_DECLSPEC ACamera: public AComponent {
    shared_ptr<ATransform> mTarget;
    FVector3F mTargetOffset;

    KH_DECL_GC()

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

    KH_DECL_CLASSINFO()

public:
    ACamera(PyObject* self): AComponent(self) {}
    virtual ~ACamera() {}

    virtual void Tick(float deltaTime) {}

    KH_DEF_GETSET_NV(const shared_ptr<ATransform>&, Target)
    KH_DEF_GETSET_NV(const FVector3F&, TargetOffset)

    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

class APawn;

class KH_ENGINE_DECLSPEC AController: public AComponent {
    shared_ptr<APawn> mPawn;

    KH_DECL_GC()

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

public:
    AController(PyObject* self);
    virtual ~AController() {}
    
    virtual void Tick(float deltaTime);

    void _Possess(shared_ptr<APawn> pawn) {}
    void _Unpossess() {}
    void Possess(shared_ptr<APawn> pawn);
    void Unpossess();

    KH_DEF_GET(const shared_ptr<APawn>&, Pawn)

    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

inline void AController::Possess(shared_ptr<APawn> pawn) {
    call_method<void>(mSelf, "Possess", pawn);
}

inline void AController::Unpossess() {
    call_method<void>(mSelf, "Unpossess");
}

class KH_ENGINE_DECLSPEC APlayerController: public AController {
    shared_ptr<CPlayer> mPlayer;
    shared_ptr<ACamera> mCamera;

    KH_DECL_GC()

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

public:
    APlayerController(PyObject* self);
    virtual ~APlayerController() {}
    
    virtual void Tick(float deltaTime);

    KH_DEF_GETSET(const shared_ptr<CPlayer>&, Player)
    KH_DEF_GETSET_NV(const shared_ptr<ACamera>&, Camera)

    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

class KH_ENGINE_DECLSPEC APawn: public AComponent {
    shared_ptr<AController> mController;

    KH_DECL_GC()

protected:
    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

public:
    APawn(PyObject* self);
    virtual ~APawn() {}
    
    virtual void Tick(float deltaTime);

    void _OnPossessed(shared_ptr<AController> controller) {}
    void _OnUnpossessed() {}
    void OnPossessed(shared_ptr<AController> controller);
    void OnUnpossessed();

    KH_DEF_GET(const shared_ptr<AController>&, Controller)

    friend void _InitActorClasses();
    friend void _InitActorBindings();
};

inline void APawn::OnPossessed(shared_ptr<AController> controller) {
    call_method<void>(mSelf, "OnPossessed", controller);
}

inline void APawn::OnUnpossessed() {
    call_method<void>(mSelf, "OnUnpossessed");
}

class KH_ENGINE_DECLSPEC ANetwork: public AComponent {
    bool mHasNativeRep;
    bool mUseNativeRep;
    bool mHasPythonRep;
    bool mUsePythonRep;
    bool mInitial;
    ENetRole mRole;
    ENetRole mRemoteRole;
    object mActorClass;
    // Native replication
    std::vector<byte> mRecentNative;
    std::vector<sint16> mIndices;
    std::vector<FFieldInfo> mFullFieldInfo;
    const FFieldInfo* mRoleInfo;
    const FFieldInfo* mRemoteRoleInfo;
    // Python Replication
    //tuple mNetVarsList;
    //dict mNetVarsDict;
    //list mRecentPython;
    //object mPickleFunc;
    //object mPickleProtocol;

protected:
    kh_pycall object ReplicatePython();
    kh_pycall void UpdatePython(object datastr);
    kh_pycall object PickleDumpImpl(object);

    void _OnInit(shared_ptr<CActor> owner);
    void _OnExit();

public:
    ANetwork(PyObject* self);
    virtual ~ANetwork();

    virtual void Tick(float deltaTime) {}

    void InitNativeRep();
    void ExitNativeRep();
    kh_pycall void InitPythonRep();
    kh_pycall void ExitPythonRep();
    bool Replicate(rn::BitStream* out, bool initial);
    bool Update(rn::BitStream* in);

    KH_DEF_GET(const object&, ActorClass)
    KH_DEF_GETSET(bool, UseNativeRep)

    friend void _InitActorClasses();
    friend void _InitActorBindings();
    friend void _ExitActorClasses();
};

inline void ANetwork::InitPythonRep() {
    call_method<void>(mSelf, "InitPythonRep");
}

inline void ANetwork::ExitPythonRep() {
    call_method<void>(mSelf, "ExitPythonRep");
}

inline object ANetwork::ReplicatePython() {
    return call_method<object>(mSelf, "ReplicatePython");
}

inline void ANetwork::UpdatePython(object datastr) {
    call_method<void>(mSelf, "UpdatePython", datastr);
}

inline object ANetwork::PickleDumpImpl(object obj) {
    return call_method<object>(mSelf, "PickleDumpImpl", obj);
}

struct PSCActor: public pickle_suite {
    static bool getstate_manages_dict() { return true; }
    static tuple getstate(CActor& actor);
    static void setstate(CActor& actor, tuple state);
};

/// An entry in CActor's component list.
/// This provides easy access to the component's type and support for sorting.
/// Instances of this class must always point to a valid component and type.
struct FComponentEntry {
    /// The held component
    shared_ptr<AComponent> Component;
    /// The Python type of the component
    handle<PyTypeObject> Type;

    FComponentEntry(shared_ptr<AComponent> c):
        Component(c),
        Type(c->GetTypeHandle()) {}

    /// Sort by priority support.
    bool operator<(const FComponentEntry& other) const { return *Component < *other.Component; }

    bool operator==(const FComponentEntry& other) const { return Type.get() == other.Type.get(); }
    bool operator!=(const FComponentEntry& other) const { return Type.get() != other.Type.get(); }

    operator shared_ptr<AComponent>() const { return Component; }
};

/// Component slot index. Names are not all-caps in order to be macro-compatible
/// This must be kept in synch with the type_info list in CActor::AddComponent()
/// Slotted components are accessed through GetTYPENAME()
enum EComponentSlot {
    SLOT_Transform = 0,
    SLOT_Movement,
    SLOT_Render,
    SLOT_Physics,
    SLOT_Camera,
    SLOT_Pawn,
    SLOT_PlayerController,
    SLOT_LAST
};

#define GET_SLOT(TYPE) \
    inline const shared_ptr<A##TYPE>& Get##TYPE() const { \
        return (shared_ptr<A##TYPE>&)mComponentSlots[(uint)SLOT_##TYPE]; \
    }

/// The main component container class.
/// Represents a single object in the game level composed of components.
class KH_ENGINE_DECLSPEC CActor: public core::CObject {
public:
    typedef std::vector<shared_ptr<CActor>> ChildrenType;
    typedef std::vector<FComponentEntry> ComponentsType;

private:
    uint32 mID;
    /// The actor's tag.
    unicode mTag;
    /// The level that owns this actor. An actor is considered invalid if
    /// it has no level.
    shared_ptr<CLevel> mLevel;
    /// The actor that owns this actor
    shared_ptr<CActor> mOwner;
    /// The actors owned by this actor
    ChildrenType mChildren;
    /// True when the actor needs to be deleted at the first opportunity.
    bool mDeleteMe;

    /// The components held by the actor. The most derived type must be unique.
    ComponentsType mComponents;
    /// Fast lookup slots for common components. This is synchronized with
    /// EComponentSlot.
    shared_ptr<AComponent> mComponentSlots[SLOT_LAST];

    void SetLevel(const shared_ptr<CLevel>& level);

    KH_DECL_GC()

protected:
    //KH_DECL_CLASSINFO()
    /// Handles for the types allowed for the component slots.
    /// AddComponent() will allow subclasses of these types in the slots.
    static handle<PyTypeObject> msComponentSlotTypes[SLOT_LAST];

public:
    CActor(PyObject* self);
    virtual ~CActor();

    /// Update the actor's components
    virtual void Tick(float deltaTime);
    /// Get a component using its Python type. Allows subclasses.
    shared_ptr<AComponent> GetComponent(object cls) const;
    /// Get a component using its Python type, only if the most derived
    /// type is cls.
    shared_ptr<AComponent> GetComponentExact(object cls) const;
    /// Implementation of GetComponentExact<T>()
    shared_ptr<AComponent> GetComponentExact(py::type_info) const;
    /// Retrieve component based on its most derived Boost.Python-created
    /// type.
    template <class T> shared_ptr<T> GetComponentExact() const;

    GET_SLOT(Transform)
    GET_SLOT(Movement)
    GET_SLOT(Render)
    GET_SLOT(Physics)
    GET_SLOT(Camera)
    GET_SLOT(Pawn)
    GET_SLOT(PlayerController)

    /// Add a component to this actor. Calls OnInit() on the component.
    void AddComponent(const shared_ptr<AComponent>&);
    /// Remove a component from this actor. Calls OnExit() on the component.
    void RemoveComponent(const shared_ptr<AComponent>&);
    /// Call OnExit() for all components and remove them.
    void ClearComponents();

    void OnInit(uint32 id, const shared_ptr<CLevel>& level,
                           const shared_ptr<CActor>& owner);

    void OnExit();

    /// Actual OnCreated() implementation
    void _OnCreated();
    /// Actual OnDestroyed() implementation
    void _OnDestroyed();
    /// Called during actor creation from CLevel::CreateActor()
    /// \pycall
    void OnCreated();
    /// Called during actor destruction from CLevel::DestroyActor()
    /// \pycall
    void OnDestroyed();
    void _OnGameStarted(shared_ptr<CGame> game);
    void _OnGameStopped();
    /// \pycall
    void OnGameStarted(shared_ptr<CGame> game);
    /// \pycall
    void OnGameStopped();

    KH_DEF_GET(uint32, ID)
    KH_DEF_GETSET(const unicode&, Tag)
    KH_DEF_GET(const shared_ptr<CLevel>&, Level)
    KH_DEF_GET(const shared_ptr<CActor>&, Owner)
    void SetOwner(const shared_ptr<CActor>&);
    bool GetNoDelete() const;
    KH_DEF_GET(bool, DeleteMe)
    KH_DEF_GET(const ComponentsType&, Components)

    int GetComponentCount() const {
        return mComponents.size();
    }

    shared_ptr<AComponent> GetComponent(int index) const {
        return mComponents.at(index).Component;
    }

    friend void _InitActorClasses();
    friend void _InitActorBindings();
    friend void _ExitActorClasses();
    friend class CLevel;
    friend struct PSCActor;
};

#undef GET_SLOT

template <class T>
shared_ptr<T> CActor::GetComponentExact() const {
    shared_ptr<AComponent> c = GetComponentExact(type_id<T>());
    return boost::dynamic_pointer_cast<T>(c);
}

inline void CActor::OnCreated() {
    call_method<void>(mSelf, "OnCreated");
}

inline void CActor::OnDestroyed() {
    call_method<void>(mSelf, "OnDestroyed");
}

inline void CActor::OnGameStarted(shared_ptr<CGame> game) {
    call_method<void>(mSelf, "OnGameStarted", game);
}

inline void CActor::OnGameStopped() {
    call_method<void>(mSelf, "OnGameStopped");
}

inline bool CActor::GetNoDelete() const {
    for (uint i = 0; i < mComponents.size(); i++)
        if (mComponents[i].Component->GetNoDelete())
            return true;
    return false;
}

// Old pre-component system code. Uncommented but left in for reference.
/*
class KH_ENGINE_DECLSPEC AActor: public core::CObject, public FDrawable, public rn::Replica3 {
    typedef std::vector<shared_ptr<AActor>> AttachedType;
    typedef std::vector<shared_ptr<AActor>> ChildrenType;

    unicode mName;
    object mNameHash;
    shared_ptr<CLevel> mLevel;
    shared_ptr<AActor> mOwner;
    AttachedType mAttached;
    shared_ptr<AActor> mAttachedTo;
    ChildrenType mChildren;
    bool mStatic;
    bool mNoDelete;
    bool mDeleteMe;
    // Movement
    FVector3F mPosition;
    FVector3F mVelocity;
    FVector3F mAcceleration;
    EDirection mDirection; // sprite direction
    bool mHasMoved; // has moved since the last frame was drawn
    FTileGroupNumber mTileGroupNumber;
    // Physics
    bool mCollideTiles;
    bool mCollideActors;
    int mCollisionLayer;
    FRectF mBounds;
    double mLastActorHitTime;
    AActor* mLastActorHit; // used only for checking in MoveActor()
    // Rendering
    EActorRenderType mRenderType;
    bool mHidden;
    // Networking
    shared_ptr<CActorReplicator> mReplicator;

    void ResetTileGroupNumber();

    KH_DECL_GC()

protected:
    //KH_DECL_CLASSINFO()
    bool mNetDirty;
    bool mNetInitial;
    bool mNetOwner;
    bool mNetSkipActorReplication;
    ENetRole mRole;
    ENetRole mRemoteRole;

    void NetReference();
    void NetDereference();
    float Sleep(float time, uint8 group=core::CTasker::CURRENT_GROUP);
    float Yield(uint8 group=core::CTasker::CURRENT_GROUP);

    static object msSimulatedNoOpFunc;
    static object msSimulatedNoOpMeth;
    static object msSimulatedStr;
    static getattrofunc msBaseGetAttr;
    static setattrofunc msBaseSetAttr;
    static PyObject* _GetAttr(PyObject*, PyObject*);
    static int _SetAttr(PyObject*, PyObject*, PyObject*);

public:
    AActor(PyObject* self);
    virtual ~AActor();

    virtual void Tick(float deltaTime);
    virtual sint16* GetNativeRepVars(sint16* indicies, const byte* recent, const FFieldInfo* fieldinfo);
    void EnsureReplicator();
    void CreateReplicator();
    void DestroyReplicator();
    virtual void Move(const FVector3F& delta);
    virtual void Attach(shared_ptr<AActor> actor);
    virtual void Detach(shared_ptr<AActor> actor);
    virtual void Draw(CEngine& engine);
    virtual object CreateEventTasklet(const char* methname);
    virtual object CreateEventTasklet(object methname);
    shared_ptr<AActor> GetTopOwner() const;

    void _OnCreated();
    void _OnDestroyed();
    virtual void OnCreated();
    virtual void OnDestroyed();
    void _OnTouched(shared_ptr<AActor> other);
    virtual void OnTouched(shared_ptr<AActor> other);
    void _OnGainedChild(shared_ptr<AActor> other);
    void _OnLostChild(shared_ptr<AActor> other);
    virtual void OnGainedChild(shared_ptr<AActor> other);
    virtual void OnLostChild(shared_ptr<AActor> other);

    bool IsValid() const; // __nonzero__ impl
    KH_DEF_GETSET(bool, NetDirty)
    KH_DEF_GETSET(bool, NetInitial)
    KH_DEF_GET(const unicode&, Name)
    KH_DEF_GET(const object&, NameHash)
    sint32 GetNameHashAsInt() const;
    KH_DEF_GET(const shared_ptr<CLevel>&, Level)
    KH_DEF_GET(const shared_ptr<AActor>&, Owner)
    void SetOwner(const shared_ptr<AActor>& other);
    KH_DEF_GET(const shared_ptr<AActor>&, AttachedTo)
    KH_DEF_GET(const std::vector<shared_ptr<AActor>>&, Attached)
    KH_DEF_GET(bool, Static)
    KH_DEF_GET(bool, NoDelete)
    KH_DEF_GET(bool, DeleteMe)
    KH_DEF_GET(const FVector3F&, Position)
    void SetPosition(const FVector3F& v);
    KH_DEF_GETSET_NV(const FVector3F&, Velocity)
    KH_DEF_GETSET_NV(const FVector3F&, Acceleration)
    KH_DEF_GETSET_NV(EDirection, Direction)
    KH_DEF_GETSET_NV(bool, CollideTiles)
    KH_DEF_GET(bool, CollideActors)
    void SetCollideActors(bool);
    KH_DEF_GET(int, CollisionLayer)
    void SetCollisionLayer(int layer);
    KH_DEF_GETSET_NV(const FRectF&, Bounds)
    KH_DEF_GET(FTileGroupNumber, TileGroupNumber)
    KH_DEF_GET(EActorRenderType, RenderType)
    KH_DEF_GETSET_NV(bool, Hidden)

    KH_DEF_GETSET(ENetRole, Role)
    KH_DEF_GET(ENetRole, RemoteRole)
    void SetRemoteRole(ENetRole role);
    KH_DEF_GETSET(bool, NetSkipActorReplication)

    // Replica3 methods
    virtual void WriteAllocationID(rn::Connection_RM3* dest, rn::BitStream* out) const;
    virtual rn::RM3ConstructionState QueryConstruction(rn::Connection_RM3* dest, rn::ReplicaManager3* rm);
    virtual rn::RM3DestructionState QueryDestruction(rn::Connection_RM3 *dest, rn::ReplicaManager3 *rm);
    virtual bool QueryRemoteConstruction(rn::Connection_RM3* source);
    virtual void SerializeConstruction(rn::BitStream* bs, rn::Connection_RM3* dest);
    virtual bool DeserializeConstruction(rn::BitStream* bs, rn::Connection_RM3* source);
    virtual void SerializeDestruction(rn::BitStream* bs, rn::Connection_RM3* dest);
    virtual bool DeserializeDestruction(rn::BitStream* bs, rn::Connection_RM3* source);
    virtual rn::RM3ActionOnPopConnection QueryActionOnPopConnection(RakNet::Connection_RM3 *dropped) const;
    virtual rn::RM3QuerySerializationResult QuerySerialization(RakNet::Connection_RM3 *dest);
    virtual rn::RM3SerializationResult Serialize(rn::SerializeParameters* sp);
    virtual void Deserialize(rn::DeserializeParameters* dp);
    virtual void DeallocReplica(rn::Connection_RM3* source);
    //virtual void BroadcastDestruction();

    static FTileGroupNumber CalculateTileGroupNumber(const FVector3F& pos);

    friend class CLevel;
    // _CreateActor, _DestroyActor
    friend class CActorReplicator;
    friend void _InitActorBindings();
    friend void _FiniActorBindings();
};

inline bool AActor::IsValid() const {
    return mLevel;
}

inline sint32 AActor::GetNameHashAsInt() const {
    return static_cast<sint32>(PyInt_AS_LONG(mNameHash.ptr()));
}

inline shared_ptr<AActor> AActor::GetTopOwner() const {
    shared_ptr<AActor> owner = mOwner;
    while (owner)
        owner = owner->GetOwner();
    return owner;
}

inline FTileGroupNumber AActor::CalculateTileGroupNumber(const FVector3F& pos) {
    FTileGroupNumber n;
    n.X = int(pos.X) / 64;
    n.Y = int(pos.Y) / 64;
    return n;
}

inline void AActor::SetPosition(const FVector3F& v) {
    mPosition = v;
    mHasMoved = true;
    mNetDirty = true;
    //ResetTileGroupNumber();
}

inline void AActor::ResetTileGroupNumber() {
    mTileGroupNumber = CalculateTileGroupNumber(mPosition);
}

inline void AActor::EnsureReplicator() {
    if (!mReplicator) {
        CreateReplicator();
    }
}

inline void AActor::OnTouched(shared_ptr<AActor> other) {
    call_method<void>(mSelf, "OnTouched", other);
}

inline void AActor::OnGainedChild(shared_ptr<AActor> other) {
    call_method<void>(mSelf, "OnGainedChild", other);
}

inline void AActor::OnLostChild(shared_ptr<AActor> other) {
    call_method<void>(mSelf, "OnLostChild", other);
}

class KH_ENGINE_DECLSPEC CActorReplicator: public core::CObject {
    bool mHasNativeReplication;
    bool mInitial;
    shared_ptr<AActor> mActor;
    object mActorClass;
    // Native replication
    std::vector<byte> mRecentNative;
    std::vector<sint16> mIndices;
    std::vector<FFieldInfo> mFullFieldInfo;
    const FFieldInfo* mRoleInfo;
    const FFieldInfo* mRemoteRoleInfo;
    // Python Replication
    tuple mNetVarsList;
    dict mNetVarsDict;
    list mRecentPython;
    object mPickleFunc;
    object mPickleProtocol;

    KH_DECL_GC()

public:
    CActorReplicator(PyObject* self);
    virtual ~CActorReplicator() {}

    void BindActor(shared_ptr<AActor>);
    void _BindActor(shared_ptr<AActor>);
    void UnbindActor();
    object ReplicatePython();
    void UpdatePython(object datastr);
    bool ReplicateNative(rn::BitStream* out, bool initial);
    bool UpdateNative(rn::BitStream* in);
    object PickleDumpImpl(object);

    KH_DEF_GET(const shared_ptr<AActor>&, Actor)
    KH_DEF_GET(const object&, ActorClass)
    KH_DEF_GETSET(bool, HasNativeReplication)

    static void InitClass();

    friend void _InitActorBindings();

    const static FFieldInfo::IndexType FI_LIMIT = 0xEFFF;
    const static FFieldInfo::IndexType FI_PYTHON = 0xF000;
    const static FFieldInfo::IndexType FI_END = 0xFFFF;
};

inline void AActor::OnCreated() {
    call_method<void>(mSelf, "OnCreated");
}

inline void AActor::OnDestroyed() {
    call_method<void>(mSelf, "OnDestroyed");
}

inline void CActorReplicator::UpdatePython(object datastr) {
    call_method<object>(mSelf, "UpdatePython", datastr);
}

inline object CActorReplicator::PickleDumpImpl(object obj) {
    return call_method<object>(mSelf, "PickleDumpImpl", obj);
}
*/

}} // namespace Kharlia

KH_HAS_BACK_REFERENCE(kharlia::engine::AComponent)
KH_HAS_BACK_REFERENCE(kharlia::engine::ATransform)
KH_HAS_BACK_REFERENCE(kharlia::engine::AMovement)
KH_HAS_BACK_REFERENCE(kharlia::engine::ARender)
KH_HAS_BACK_REFERENCE(kharlia::engine::APhysics)
KH_HAS_BACK_REFERENCE(kharlia::engine::ACamera)
//KH_HAS_BACK_REFERENCE(kharlia::engine::AReplicator)
KH_HAS_BACK_REFERENCE(kharlia::engine::AController)
KH_HAS_BACK_REFERENCE(kharlia::engine::APlayerController)
KH_HAS_BACK_REFERENCE(kharlia::engine::APawn)
KH_HAS_BACK_REFERENCE(kharlia::engine::ANetwork)
KH_HAS_BACK_REFERENCE(kharlia::engine::CActor)

//KH_HAS_BACK_REFERENCE(kharlia::engine::AActor)
//KH_HAS_BACK_REFERENCE(kharlia::engine::CActorReplicator)

#endif